﻿Imports CrystalDecisions.CrystalReports.Engine
Imports CrystalDecisions.Shared
Imports System.IO
Imports org.codegen.win.controls
Imports org.model.lib.db

<ComClass(CRReportViewer.ClassId, CRReportViewer.InterfaceId, CRReportViewer.EventsId)> _
Public Class CRReportViewer

#Region "COM GUIDs"

    ' These  GUIDs provide the COM identity for this class 
    ' and its COM interfaces. If you change them, existing 
    ' clients will no longer be able to access the class.
    Public Const ClassId As String = "0541482b-1cc4-4875-b43d-068dbe7eaa1c"
    Public Const InterfaceId As String = "8ad43baa-49d6-4d36-80cb-61cc19fbfc29"
    Public Const EventsId As String = "b52cc9cb-3d2a-4afa-a991-23761b401a6f"
    Private Const STR_CRITERIA_PARAMETER_NAME As String = "Criteria"

#End Region

    ' A creatable COM class must have a Public Sub New() 
    ' with no parameters, otherwise, the class will not be 
    ' registered in the COM registry and cannot be created 
    ' via CreateObject.
    Public Sub New()
        MyBase.New()
    End Sub

    Private _usernane As String
    Private _password As String
    Private _reportConnString As String
    Private _showCriteriaForm As Boolean
    Private _ReportsProvider As ICrystalReportMatadataProvider
    Private _report As ReportMatadata
    Private _IReportInstanceLoader As IReportInstanceLoader

    Private criteriaProcessor As ReportCriteriaProcessor = New ReportCriteriaProcessor

    Public Sub askForCriteriaAndShowReport()

        Try

            If Me.ReportMetaData.Criteria Is Nothing OrElse Me.ReportMetaData.Criteria.Count = 0 Then
                Call ShowReportFromType()
            Else
                Using f As New frmCriteria

                    f.setReportMetadata(Me.ReportMetaData)

                    Do While True

                        winUtils.HourglassOff()
                        f.ShowDialog()
                        winUtils.HourglassOn() 'reset to hourglass while report is beiong prepared

                        If Me.ReportMetaData.ReportService IsNot Nothing Then
                            Me.ReportMetaData.ReportService.prepareReport(Me.ReportMetaData)
                        End If

                        If f.DialogResult = DialogResult.OK Then
                            Call ShowReportFromType()

                            If Me.ReportMetaData.ReportService IsNot Nothing Then
                                Me.ReportMetaData.ReportService.closeReport(Me.ReportMetaData)
                            End If

                        Else
                            Exit Do
                        End If
                    Loop

                End Using
            End If

        Finally
            winUtils.HourglassOff()
        End Try
    End Sub

    Public Sub setCriterionValue(ByVal criterionName As String, ByVal value As Object)

        Dim lst As List(Of CriterionMetadata) = Me.ReportMetaData.Criteria
        For Each c As CriterionMetadata In lst
            If c.Name.ToLower = criterionName.ToLower Then
                c.selectedvalue = value
                Return
            End If
        Next
    End Sub


    ''' <summary>
    ''' If you are going to use this function, the rpt.metadata should have set 
    ''' values.  The criteria form will not be shown!
    ''' </summary>
    Public Sub ShowReport()

        Try
            winUtils.HourglassOn()

            Call ShowReportFromType()

        Finally
            winUtils.HourglassOff()
        End Try
    End Sub


    Private Sub ShowReportFromType()

        'show report from loaded type
        Dim f As frmCRViewer = Nothing
        Dim rpt As ReportClass = Nothing
        Try
            winUtils.HourglassOn()

            Using f
                f = New frmCRViewer
                rpt = Me.IReportInstanceLoader.getReportInstance(Me.ReportMetaData)

                Trace.TraceInformation("Preparing report:" & Me.ReportMetaData.DisplayName & " " & ReportMetaData.FullyQualifiedResourcePath)
                Call setReportDataSource(rpt)
                Call setReportParameters(rpt)

                Trace.TraceInformation("Opening report:" & Me.ReportMetaData.DisplayName & ": " & rpt.Rows.Count)

                f.crViewer.ReportSource = rpt
                f.ShowDialog()


            End Using

        Finally
            winUtils.HourglassOff()
        End Try
    End Sub

    Public Sub setReportDataSource(ByRef rpt As ReportClass)

        Dim rrTables As Tables = rpt.Database.Tables

        If rrTables.Count = 0 Then
            Return
        End If

        Dim crTable As Table = rrTables(0)
        Dim sql As String = "select * from " & crTable.Location

        criteriaProcessor.resetParameters()
        criteriaProcessor.report = Me.ReportMetaData
        sql = sql & criteriaProcessor.getCriteriaSQL()

        Dim lDBUtilsCurrent As DBUtils = DBUtils.Current
        Dim reportDtdr As DataTable = Nothing

        Trace.TraceInformation("Report SQL: " & sql)

        reportDtdr = lDBUtilsCurrent.getDataTableWithParams( _
                            sql, _
                            criteriaProcessor.sqlParameterValues.ToArray)

        crTable.SetDataSource(reportDtdr)

    End Sub

    Private Sub setReportParameters(ByRef report As ReportClass)

        'the STR_CRITERIA_PARAMETER_NAME is the standard parameter that is used to show the report
        Call Me.setCrystalParameterValue(report, STR_CRITERIA_PARAMETER_NAME, _
                                    Me.criteriaProcessor.getCriteriaAsString)

        'process all other parameters here and pass values
        For Each c As CriterionMetadata In Me.ReportMetaData.Criteria

            Me.setCrystalParameterValue(report, c.Name, c.selectedvalue)
            If c.isRange Then
                Call Me.setCrystalParameterValue(report, c.Name2, c.selectedvalue2)
            End If

        Next

    End Sub

    Public Sub setCrystalParameterValue(ByRef rpt As ReportClass, _
                                            ByVal parameterName As String, _
                                            ByVal val As Object)

        If rpt.ParameterFields(parameterName) Is Nothing Then

            Return
        End If

        If val Is Nothing Then

            Select Case rpt.ParameterFields(parameterName).ParameterValueKind
                Case CrystalDecisions.[Shared].ParameterValueKind.BooleanParameter
                    val = False

                Case CrystalDecisions.[Shared].ParameterValueKind.CurrencyParameter, _
                        CrystalDecisions.[Shared].ParameterValueKind.NumberParameter

                    val = 0

                Case CrystalDecisions.[Shared].ParameterValueKind.DateParameter, _
                      CrystalDecisions.[Shared].ParameterValueKind.DateTimeParameter, _
                       CrystalDecisions.[Shared].ParameterValueKind.TimeParameter

                    val = DateSerial(1900, 1, 1)


                Case CrystalDecisions.[Shared].ParameterValueKind.StringParameter
                    val = String.Empty

            End Select


        End If

        Dim paramDV As ParameterDiscreteValue = New ParameterDiscreteValue()
        paramDV.Value = val

        rpt.ParameterFields(parameterName).CurrentValues.Clear()
        rpt.ParameterFields(parameterName).DefaultValues.Clear()
        rpt.ParameterFields(parameterName).CurrentValues.Add(paramDV)
        rpt.ParameterFields(parameterName).HasCurrentValue = True

    End Sub

    Public Property IReportInstanceLoader() As IReportInstanceLoader
        Get
            If _IReportInstanceLoader Is Nothing Then
                _IReportInstanceLoader = New ReportInstanceLoader
            End If
            Return _IReportInstanceLoader
        End Get
        Set(ByVal value As IReportInstanceLoader)
            _IReportInstanceLoader = value
        End Set
    End Property

    Public Property ReportMetaData() As ReportMatadata
        Get
            Return _report
        End Get
        Set(ByVal value As ReportMatadata)
            _report = Value
        End Set
    End Property
    Public Property ReportConnString() As String
        Get
            Return _reportConnString
        End Get
        Set(ByVal value As String)
            _reportConnString = value
        End Set
    End Property

    Private ReadOnly Property ReportsProvider() As ICrystalReportMatadataProvider
        Get
            If _ReportsProvider Is Nothing Then
                _ReportsProvider = New XMLFileReportDefinitionsProvider

            End If

            Return _ReportsProvider

        End Get
    End Property

End Class


